package com.smart.community.user.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.smart.community.commons.cache.DataScopeInfo;
import com.smart.community.commons.dto.property.PropertyCompanyDTO;
import com.smart.community.commons.enums.SystemStatusEnum;
import com.smart.community.commons.enums.UserTypeEnum;
import com.smart.community.commons.exception.AuthenticationException;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.feign.property.service.IUserPropertyCompanyAuthFeign;
import com.smart.community.feign.property.service.DataScopeFeign;
import com.smart.community.user.dto.LoginDTO;
import com.smart.community.user.dto.AppLoginDTO;
import com.smart.community.user.dto.RegisterDTO;
import com.smart.community.user.entity.LoginLog;
import com.smart.community.user.entity.Permission;
import com.smart.community.user.entity.User;
import com.smart.community.user.entity.UserRole;
import com.smart.community.user.service.AuthService;
import com.smart.community.user.service.LoginLogService;
import com.smart.community.user.service.PermissionService;
import com.smart.community.user.service.RoleService;
import com.smart.community.user.service.UserRoleService;
import com.smart.community.user.service.UserService;
import com.smart.community.user.vo.LoginVO;
import com.smart.community.user.vo.AppLoginVO;
import com.smart.community.user.vo.RoleVO;
import com.smart.community.user.vo.UserVO;

import lombok.extern.slf4j.Slf4j;

/**
 * 认证服务实现类
 * 
 * @author Wu.Liang
 * @since 2024-12-21
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private UserService userService;

    @Autowired
    private LoginLogService loginLogService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private IUserPropertyCompanyAuthFeign userPropertyCompanyAuthFeign;
    
    @Autowired
    private DataScopeFeign dataScopeFeign;

    @Override
    public LoginVO login(LoginDTO loginDTO) throws Exception {
        log.info("用户登录: {}", loginDTO.getUsername());
        
        // 根据用户名/手机号/身份证号查询用户
        User user = findUserByLoginIdentifier(loginDTO.getUsername());
        
        if (user == null) {
            recordLoginLog(null, getClientIp(), getUserAgent(), false, "用户不存在");
            throw new AuthenticationException("用户名或密码错误");
        }
        
        // 验证密码 - 使用SecurityUtils的密码验证方式
        if (!SecurityUtils.verifyPassword(loginDTO.getPassword(), user.getPassword())) {
            recordLoginLog(user.getId(), getClientIp(), getUserAgent(), false, "密码错误");
            throw new AuthenticationException("用户名或密码错误");
        }
        
        // 检查用户状态
        if (user.getStatus() != null && user.getStatus() == 0) {
            recordLoginLog(user.getId(), getClientIp(), getUserAgent(), false, "用户已被禁用");
            throw new AuthenticationException("用户已被禁用");
        }
        
        // 检查用户是否关联了物业公司（通过用户表中的propertyCompanyId字段）
        if (user.getPropertyCompanyId() != null) {
            // 关联了物业公司的用户，需要检查物业公司审核状态
        	PropertyCompanyDTO propertyCompany = getPropertyCompanyById(user.getPropertyCompanyId());
            if (propertyCompany != null && propertyCompany.getStatus() != null && propertyCompany.getStatus() == 0) {
                recordLoginLog(user.getId(), getClientIp(), getUserAgent(), false, "关联的物业公司已被禁用");
                throw new AuthenticationException("关联的物业公司已被禁用，请联系管理员");
            }
        }
        
        // 使用SecurityUtils进行用户登录，统一用户上下文管理
        String token = SecurityUtils.login(user.getId());
        
        // 记录登录日志
        recordLoginLog(user.getId(), getClientIp(), getUserAgent(), true, "登录成功");
        
        // 构建返回结果
        UserVO userVO = new UserVO();
        userVO.setId(user.getId());
        userVO.setUsername(user.getUsername());
        userVO.setNickname(user.getRealName()); // 使用realName作为nickname
        userVO.setRealName(user.getRealName());
        userVO.setEmail(user.getEmail());
        userVO.setPhone(user.getPhone());
        userVO.setAvatar(user.getAvatar());
        userVO.setUserType(user.getUserType());
        userVO.setStatus(user.getStatus());
        userVO.setLastLoginTime(user.getLastLoginTime());
        userVO.setLastLoginIp(user.getLastLoginIp());
        userVO.setCreateTime(user.getCreateTime());
        userVO.setUpdateTime(user.getUpdateTime());

        // 查询权限标识列表
        List<String> permissions = new ArrayList<>();
        try {
            List<Permission> permissionList = permissionService.getPermissionsByUserId(user.getId());
            if (permissionList != null) {
                permissions = permissionList.stream()
                    .filter(p -> p != null && p.getPermissionCode() != null)
                    .map(p -> p.getPermissionCode())
                    .collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.warn("查询用户权限失败，用户ID: {}", user.getId(), e);
        }
        
        // 查询角色标识列表（修正：返回角色编码而非ID）
        List<String> roles = new ArrayList<>();
        try {
            List<UserRole> userRoleList = userRoleService.getUserRolesByUserId(user.getId());
            if (userRoleList != null && !userRoleList.isEmpty()) {
                for (UserRole ur : userRoleList) {
                    if (ur != null && ur.getRoleId() != null) {
                        RoleVO roleVO = roleService.getRole(ur.getRoleId());
                        if (roleVO != null && roleVO.getRoleCode() != null) {
                            roles.add(roleVO.getRoleCode());
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("查询用户角色失败，用户ID: {}", user.getId(), e);
        }
        
        // 设置用户权限和角色
        userVO.setPermissions(permissions);
        userVO.setRoles(roles);
        
        // 构建登录返回结果
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        loginVO.setUser(userVO);
        loginVO.setUserId(user.getId());
        loginVO.setUsername(user.getUsername());
        loginVO.setRealName(user.getRealName());
        loginVO.setNickname(user.getRealName());
        loginVO.setAvatar(user.getAvatar());
        loginVO.setUserType(user.getUserType());
        loginVO.setPermissions(permissions);
        loginVO.setRoles(roles);
        
        return loginVO;
    }

    @Override
    public void register(RegisterDTO registerDTO) throws Exception {
        log.info("用户注册: {}", registerDTO.getUsername());
        
        // 检查用户名是否已存在
        User existingUser = userService.lambdaQuery()
                .eq(User::getUsername, registerDTO.getUsername())
                .one();
        
        if (existingUser != null) {
            throw new AuthenticationException("用户名已存在");
        }
        
        // 创建新用户 - 使用SecurityUtils的密码加密方式
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(SecurityUtils.encryptPassword(registerDTO.getPassword()));
        user.setRealName(registerDTO.getRealName());
        user.setEmail(registerDTO.getEmail());
        user.setPhone(registerDTO.getPhone());
        user.setUserType(UserTypeEnum.NORMAL_USER.getCode());
        user.setStatus(SystemStatusEnum.ENABLED.getCode());
        
        userService.save(user);
        
        log.info("用户注册成功: {}", registerDTO.getUsername());
    }

    @Override
    public void logout() throws Exception {
        Long userId = SecurityUtils.getCurrentUserId();
        
        // 清除用户权限缓存
        clearUserPermissionCache(userId);
        
        // 使用SecurityUtils进行用户登出
        SecurityUtils.logout();
        
        log.info("用户登出成功");
    }
        
    /**
     * 清除用户权限缓存
     * 根据《智慧社区微服务架构总览.md》标准，确保权限缓存的一致性
     */
    private void clearUserPermissionCache(Long userId) {
        try {
            // 清除数据权限范围缓存
            String dataScopeCacheKey = "data_scope:user:" + userId;
            redisTemplate.delete(dataScopeCacheKey);
            
            // 清除其他相关权限缓存
            String[] cacheKeys = {
                "user:super:admin:" + userId,
                "user:data:scope:" + userId,
                "user:property:company:ids:" + userId,
                "user:community:ids:" + userId,
                "permission:menu:user:" + userId,
                "permission:data:scope:user:" + userId
            };
            
            for (String cacheKey : cacheKeys) {
                redisTemplate.delete(cacheKey);
            }
            
            log.info("用户退出登录，已清除权限缓存，用户ID: {}", userId);
        } catch (Exception e) {
            log.warn("清除用户权限缓存失败，用户ID: {}", userId, e);
        }
    }

    @Override
    public String refreshToken() {
        try {
            if (SecurityUtils.isLogin()) {
                // Sa-Token会自动刷新token，这里直接返回当前token
                return SecurityUtils.getTokenValue();
            }
        } catch (Exception e) {
            log.warn("刷新Token失败", e);
        }
        return null;
    }

    @Override
    public UserVO getCurrentUser() {
        try {
            if (!SecurityUtils.isLogin()) {
                return null;
            }
            
            Long userId = SecurityUtils.getCurrentUserId();
            if (userId == null) {
                return null;
            }
            
            User user = userService.getById(userId);
            if (user == null) {
                return null;
            }
            
            UserVO userVO = new UserVO();
            userVO.setId(user.getId());
            userVO.setUsername(user.getUsername());
            userVO.setNickname(user.getRealName());
            userVO.setRealName(user.getRealName());
            userVO.setEmail(user.getEmail());
            userVO.setPhone(user.getPhone());
            userVO.setAvatar(user.getAvatar());
            userVO.setUserType(user.getUserType());
            userVO.setStatus(user.getStatus());
            userVO.setLastLoginTime(user.getLastLoginTime());
            userVO.setLastLoginIp(user.getLastLoginIp());
            userVO.setCreateTime(user.getCreateTime());
            userVO.setUpdateTime(user.getUpdateTime());
            
            return userVO;
        } catch (Exception e) {
            log.warn("获取当前用户信息失败", e);
            return null;
        }
    }

    @Override
    public void resetPassword(Long userId, String newPassword) throws Exception {
        User user = userService.getById(userId);
        if (user == null) {
            throw new AuthenticationException("用户不存在");
        }
        
        user.setPassword(SecurityUtils.encryptPassword(newPassword));
        userService.updateById(user);
        
        log.info("用户密码重置成功，用户ID: {}", userId);
    }

    @Override
    public void sendResetPasswordEmail(String email) throws Exception {
        // 实现发送重置密码邮件的逻辑
        log.info("发送重置密码邮件: {}", email);
    }

    @Override
    public boolean validateResetToken(String token) {
        // 实现验证重置密码Token的逻辑
        return false;
    }

    @Override
    public void recordLoginLog(Long userId, String ip, String userAgent, boolean success, String message) throws Exception {
        LoginLog loginLog = new LoginLog();
        
        // 处理userId为null的情况，设置为0表示未知用户
        if (userId != null) {
            loginLog.setUserId(userId);
        } else {
            loginLog.setUserId(0L); // 设置为0表示未知用户
        }
        
        loginLog.setLoginIp(ip);
        loginLog.setLoginStatus(success ? 0 : 1); // 0成功 1失败
        loginLog.setLoginMessage(message);
        loginLog.setLoginTime(LocalDateTime.now());
        loginLog.setBrowser(parseBrowserInfo(userAgent));
        loginLog.setOs(parseOsInfo(userAgent));
        
        // 获取用户名
        if (userId != null) {
            try {
                User user = userService.getById(userId);
                if (user != null) {
                    loginLog.setUsername(user.getUsername());
                } else {
                    loginLog.setUsername("未知用户");
                }
            } catch (Exception e) {
                log.warn("获取用户名失败，用户ID: {}", userId, e);
                loginLog.setUsername("未知用户");
            }
        } else {
            loginLog.setUsername("未知用户");
        }
        
        // 设置其他必要字段
        loginLog.setStatus(1); // 默认状态
        loginLog.setCreateTime(LocalDateTime.now());
        loginLog.setUpdateTime(LocalDateTime.now());
        loginLog.setDeleted(0); // 未删除
        loginLog.setLoginType(1); // 默认登录类型：用户名密码
        loginLog.setOnlineDuration(0L); // 默认在线时长
        
        loginLogService.save(loginLog);
    }
    
    private String parseBrowserInfo(String userAgent) {
        if (userAgent == null || userAgent.isEmpty()) {
            return "Unknown";
        }
        
        String browser = "Unknown";
        if (userAgent.contains("Chrome")) {
            browser = "Chrome";
        } else if (userAgent.contains("Firefox")) {
            browser = "Firefox";
        } else if (userAgent.contains("Safari")) {
            browser = "Safari";
        } else if (userAgent.contains("Edge")) {
            browser = "Edge";
        } else if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            browser = "Internet Explorer";
        }
        
        return browser;
    }
    
    private String parseOsInfo(String userAgent) {
        if (userAgent == null || userAgent.isEmpty()) {
            return "Unknown";
        }
        
        String os = "Unknown";
        if (userAgent.contains("Windows")) {
            os = "Windows";
        } else if (userAgent.contains("Mac")) {
            os = "macOS";
        } else if (userAgent.contains("Linux")) {
            os = "Linux";
        } else if (userAgent.contains("Android")) {
            os = "Android";
        } else if (userAgent.contains("iOS")) {
            os = "iOS";
        }
        
        return os;
    }

    @Override
    public void changePassword(Long userId, String oldPassword, String newPassword) {
        User user = userService.getById(userId);
        if (user == null) {
            throw new AuthenticationException("用户不存在");
        }
        
        // 验证旧密码
        if (!SecurityUtils.verifyPassword(oldPassword, user.getPassword())) {
            throw new AuthenticationException("旧密码错误");
        }
        
        // 更新新密码
        user.setPassword(SecurityUtils.encryptPassword(newPassword));
        user.setUpdateTime(LocalDateTime.now());
        userService.updateById(user);
        
        log.info("用户密码修改成功，用户ID: {}", userId);
    }

    @Override
    public boolean isLoggedIn() {
        return SecurityUtils.isLogin();
    }

    @Override
    public Long getCurrentUserId() {
        if (SecurityUtils.isLogin()) {
            return SecurityUtils.getCurrentUserId();
        }
        return null;
    }
        
    private PropertyCompanyDTO getPropertyCompanyById(Long propertyCompanyId) {
        try {
            return userPropertyCompanyAuthFeign.getPropertyCompanyById(propertyCompanyId);
        } catch (Exception e) {
            log.warn("获取物业公司信息失败，物业公司ID: {}", propertyCompanyId, e);
            return null;
        }
    }
        
    private String getClientIp() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                String ip = request.getHeader("X-Forwarded-For");
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("Proxy-Client-IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("WL-Proxy-Client-IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("HTTP_CLIENT_IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("HTTP_X_FORWARDED_FOR");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getRemoteAddr();
                }
                return ip;
            }
        } catch (Exception e) {
            log.warn("获取客户端IP失败", e);
        }
        return "unknown";
    }
        
    private String getUserAgent() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                return request.getHeader("User-Agent");
            }
        } catch (Exception e) {
            log.warn("获取User-Agent失败", e);
        }
        return "unknown";
    }
    
    /**
     * 根据登录标识符查找用户
     * 支持用户名、手机号、身份证号三种方式
     * 
     * @param loginIdentifier 登录标识符（用户名/手机号/身份证号）
     * @return 用户信息
     */
    private User findUserByLoginIdentifier(String loginIdentifier) {
        if (loginIdentifier == null || loginIdentifier.trim().isEmpty()) {
            return null;
        }
        
        // 1. 先尝试按用户名查询
        User user = userService.lambdaQuery()
                .eq(User::getUsername, loginIdentifier.trim())
                .one();
        
        if (user != null) {
            log.info("通过用户名找到用户: {}", loginIdentifier);
            return user;
        }
        
        // 2. 尝试按身份证号查询
        user = userService.lambdaQuery()
                .eq(User::getIdCard, loginIdentifier.trim())
                .one();
        
        if (user != null) {
            log.info("通过身份证号找到用户: {}", loginIdentifier);
            return user;
        }       
        // 3. 再尝试按手机号查询
        user = userService.lambdaQuery()
                .eq(User::getPhone, loginIdentifier.trim())
                .one();
        
        if (user != null) {
            log.info("通过手机号找到用户: {}", loginIdentifier);
            return user;
        }

        
        log.warn("未找到匹配的用户，登录标识符: {}", loginIdentifier);
        return null;
    }

    @Override
    public AppLoginVO appLogin(AppLoginDTO appLoginDTO) throws Exception {
        log.info("App端用户登录: {}, 身份类型: {}", appLoginDTO.getUsername(), appLoginDTO.getLoginIdentityType());
        
        // 1. 先执行基础登录验证（复用原有登录逻辑）
        LoginVO loginVO = login(appLoginDTO);
        
        // 2. 获取用户数据权限信息
        DataScopeInfo userDataScope = dataScopeFeign.getUserDataScope(loginVO.getUserId());
        boolean isOwnerUser = userDataScope.isOwnerUser();
        boolean isPropertyCompanyUser = userDataScope.isPropertyCompanyUser();
        boolean isSuperAdmin = userDataScope.isSuperAdmin();
        
        // 3. 根据登录身份类型进行身份验证
        if (appLoginDTO.getLoginIdentityType() == 1 && !isOwnerUser) { // 房产业主登录
            log.warn("App端业主登录失败：用户不是业主，用户ID: {}，用户名: {}", loginVO.getUserId(), loginVO.getUsername());
            recordLoginLog(loginVO.getUserId(), getClientIp(), getUserAgent(), false, "App端业主登录失败：用户不是业主");
            throw new AuthenticationException("该用户并非业主，无法以业主身份登录");
        } else if (appLoginDTO.getLoginIdentityType() == 2 && !isPropertyCompanyUser) { // 物业管理登录
            log.warn("App端物业登录失败：用户不是物业公司人员，用户ID: {}，用户名: {}", loginVO.getUserId(), loginVO.getUsername());
            recordLoginLog(loginVO.getUserId(), getClientIp(), getUserAgent(), false, "App端物业登录失败：用户不是物业公司人员");
            throw new AuthenticationException("该用户并非物业公司人员，无法以物业身份登录");
        }
        
        // 4. 创建App登录响应对象
        AppLoginVO appLoginVO = new AppLoginVO();
        // 复制基础登录信息
        appLoginVO.setToken(loginVO.getToken());
        appLoginVO.setRefreshToken(loginVO.getRefreshToken());
        appLoginVO.setExpireIn(loginVO.getExpireIn());
        appLoginVO.setUserId(loginVO.getUserId());
        appLoginVO.setUsername(loginVO.getUsername());
        appLoginVO.setRealName(loginVO.getRealName());
        appLoginVO.setNickname(loginVO.getNickname());
        appLoginVO.setAvatar(loginVO.getAvatar());
        appLoginVO.setUserType(loginVO.getUserType());
        appLoginVO.setUserTypeName(loginVO.getUserTypeName());
        appLoginVO.setLastLoginTime(loginVO.getLastLoginTime());
        appLoginVO.setLastLoginIp(loginVO.getLastLoginIp());
        appLoginVO.setUser(loginVO.getUser());
        appLoginVO.setMenuPermissions(loginVO.getMenuPermissions());
        appLoginVO.setPermissions(loginVO.getPermissions());
        appLoginVO.setRoles(loginVO.getRoles());
        
        // 5. 设置身份标识字段
        appLoginVO.setOwnerUser(isOwnerUser);
        appLoginVO.setPropertyCompanyUser(isPropertyCompanyUser);
        appLoginVO.setSuperAdmin(isSuperAdmin);
        // 设置普通用户标识：既不是业主，也不是物业公司人员，也不是超级管理员
        boolean isNormalUser = !isOwnerUser && !isPropertyCompanyUser && !isSuperAdmin;
        appLoginVO.setIsNormalUser(isNormalUser);
        
        // 6. 身份验证成功，记录登录日志
        String identityTypeName = getIdentityTypeName(appLoginDTO.getLoginIdentityType());
        recordLoginLog(loginVO.getUserId(), getClientIp(), getUserAgent(), true, 
            String.format("App端%s登录成功: %s", identityTypeName, loginVO.getUsername()));
        
        log.info("App端用户登录成功: 用户ID={}, 用户名={}, 身份类型={}, 业主={}, 物业={}, 超级管理员={}, 普通用户={}", 
            loginVO.getUserId(), loginVO.getUsername(), appLoginDTO.getLoginIdentityType(), 
            isOwnerUser, isPropertyCompanyUser, isSuperAdmin, isNormalUser);
        
        return appLoginVO;
    }
    
    /**
     * 获取身份类型名称
     * 
     * @param loginIdentityType 登录身份类型
     * @return 身份类型名称
     */
    private String getIdentityTypeName(Integer loginIdentityType) {
        if (loginIdentityType == null) {
            return "未知身份";
        }
        switch (loginIdentityType) {
            case 1:
                return "业主";
            case 2:
                return "物业";
            case 3:
                return "普通用户";
            default:
                return "未知身份";
        }
    }
}
